import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import { AxiosCanceler } from "./helper/axiosCancel";
import { checkStatus } from "./helper/checkStatus";

interface ResultData<T = any> {
	data?: T;
}
const ONE_MINUTE_SECOND = 60 * 1000;

const axiosCanceler = new AxiosCanceler();

const config = {
	baseURL:"",
	// 设置超时时间（10s）
	timeout: ONE_MINUTE_SECOND
	// // 跨域时候允许携带凭证
	// withCredentials: true
};

class RequestHttp {
	service: AxiosInstance;
	public constructor(config: AxiosRequestConfig) {
		// 实例化axios
		this.service = axios.create(config);

		/**
		 * @description 请求拦截器
		 * 客户端发送请求 -> [请求拦截器] -> 服务器
		 */
		this.service.interceptors.request.use(
			(config: AxiosRequestConfig) => {
				// * 将当前请求添加到 pending 中
				axiosCanceler.addPending(config);
				return { ...config };
			},
			(error: AxiosError) => {
				console.log(error); // for debug
				Promise.reject(error);
			}
		);

		/**
		 * @description 响应拦截器
		 *  服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
		 */
		this.service.interceptors.response.use(
			(response: AxiosResponse) => {
				const { data, config } = response;
				// * 在请求结束后，移除本次请求
				axiosCanceler.removePending(config);
				// * 登陆失效
				return data;
			},
			async (error: AxiosError) => {
				const { response } = error;
				if (response) {
					checkStatus(response.status);
				} else {
					// 服务器结果都没有返回(可能服务器错误可能客户端断网)
					if (!window.navigator.onLine) {
						// 断网处理:可以跳转到断网页面
						return;
					}
					return Promise.reject(error);
				}
			}
		);
	}

	// * 常用请求方法封装
	get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
		config.baseURL = url
		return this.service.get(url, { params, ..._object });
	}
	post<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
		config.baseURL = url
		return this.service.post(url, params, _object);
	}
	put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
		return this.service.put(url, params, _object);
	}
	delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
		return this.service.delete(url, { params, ..._object });
	}
}

export default new RequestHttp(config);
